package main

import "fmt"

// 结构体
//Go语言中基础数据类型可以表示一些事物的基本属性，但是当我们想要表达一个事物的全部或者部分属性时，这时候再用单一的基本数据类型明显就无法满足需求了，
//Go语言提供了一个中自定义的数据类型，可以封装多个基本数据类型，这种数据类型叫做结构体，英文名称struct，也就是说我们可以通过struct来定义自己的类型

// 结构体的定义：type和struct关键字来定义，具体代码格式如下：
type people struct { //结构体的名称在一个包下不能重复，字段名在结构体中必须唯一，字段类型表示字段的具体类型
	name   string //姓名
	city   string //城市
	age    int    //年龄
	gender int    //性别
}

func main() {

	//只有当结构体实例化的时候，才会真正的分配内存，也就是必须实例化之后才能使用结构体的字段。结构体本身也是一种类型，我们可以像声明内置类型一样使用var关键字来声明结构体类型
	var girlFriend people //定义结构体，结构体是值类型，定义的时候就已经创建了地址
	girlFriend.name = "ZhongMengQi"
	girlFriend.age = 20
	girlFriend.gender = 0
	girlFriend.city = "广东梅州"
	fmt.Printf("%#v\n", girlFriend)

	var girlFriend2 = new(people) //定义指针使用new去创建结构体  new 函数只会分配内存并返回该类型的指针
	girlFriend2.name = "ZhongMengQi1"
	girlFriend2.age = 21
	girlFriend2.gender = 0
	girlFriend2.city = "广东梅州"
	fmt.Printf("%#v\n", girlFriend2)

	//取结构体的地址进行实例化
	p := &people{} //这是用于创建一个指针变量，并将其指向一个新的people类型的结构体对象
	p.name = "p"
	fmt.Printf("%#v\n", p)
	//匿名结构体 :定义一些临时数据结构等场景下还可以使用匿名结构体
	var user struct {
		name string
		age  int
	}
	user.name = "zengyujie"
	user.age = 22
	fmt.Printf("%#v\n", user)

	//结构体初始化方式
	//1.键值对赋值
	p1 := people{
		name:   "p1",
		city:   "p2",
		age:    22,
		gender: 1,
	}
	fmt.Printf("%#v\n", p1)
	p2 := &people{ //new people和&people{}是一样的
		name:   "p1",
		city:   "p2",
		age:    22,
		gender: 1,
	}
	fmt.Printf("%#v\n", p2)

	//值的列表进行初始化
	p3 := people{
		"p1", "p2", 22, 1,
	}
	fmt.Printf("%#v\n", p3)

	//使用构造函数，返回指针类型
	p4 := newPeople("jiejie", "梅州", 21, 1)
	fmt.Println(p4)
	//使用构造函数返回指针类型
	p5 := newPeople("jiejie", "梅州", 21, 1)
	fmt.Println(p5)
}

// 结构体构造函数 也称结构体方法
func newPeople(name string, city string, age int, gander int) people {
	return people{
		name:   name,
		city:   city,
		age:    age,
		gender: gander,
	}

}
func newPeople2(name string, city string, age int, gander int) *people {
	return &people{
		name, city, age, gander,
	}
}

//试图 make() 一个结构体变量，会引发一个编译错误，这还不是太糟糕，
//但是 new() 一个映射并试图使用数据填充它，将会引发运行时错误！ 因为 new(Foo) 返回的是一个指向 nil 的指针，它尚未被分配内存。所以在使用 map 时要特别谨慎。
